package pl.edu.agh.uhm.upnp.discoverer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.event.Event;
import org.osgi.service.upnp.UPnPDevice;

import pl.edu.agh.uhm.discoverer.DiscovererListener;
import pl.edu.agh.uhm.discoverer.Hypervisor;
import pl.edu.agh.uhm.discoverer.HypervisorsDiscoverer;
import pl.edu.agh.uhm.discoverer.VirtualMachine;



public final class UPnPHypervisorsDiscoverer implements HypervisorsDiscoverer,ServiceListener{

	
	List<ServiceReference> vmHypervisors=new LinkedList<ServiceReference>();
	List<ServiceReference> virtualMachines=new LinkedList<ServiceReference>();
	private DiscovererListenersManager listnersManager=new DiscovererListenersManager();
	
	
	
	
	@Override
	public List<Hypervisor> getHypervisors() {
		
		List<Hypervisor> hypervisors=new ArrayList<Hypervisor>();
		for(ServiceReference device:vmHypervisors){
			
			hypervisors.add(new UPnPBasedHypervisor(device));
				
		}
		return hypervisors;
		
		
	}
	
	@Override
	public List<VirtualMachine> getVirtualMachines() {
		
		List<VirtualMachine> vms=new ArrayList<VirtualMachine>();
		for(ServiceReference device:virtualMachines){
			
			vms.add(new UPnPBasedVirtualMachine(device));
				
		}
		return vms;
		
		
	}
	
	
	public void activate(){
		
		 
		   try {
				Activator.context.addServiceListener(this,
					"(&"+
						"("+Constants.OBJECTCLASS+"="+UPnPDevice.class.getName()+")"+
						"(|("+UPnPDevice.UDN+"=*VMHypervisor*)("+UPnPDevice.UDN+"=*VritualMachine*))"+
					")"
					);
			} catch (InvalidSyntaxException e) {
				e.printStackTrace();
			}
			System.out.println("UPNP-DISCOVERER --- UPNP devices listener activated");
			ServiceReference[] roots = null; 
			try {
				roots = Activator.context.getServiceReferences(
						UPnPDevice.class.getName(),
						"(&"+
						"("+Constants.OBJECTCLASS+"="+UPnPDevice.class.getName()+")"+
						"("+UPnPDevice.UDN+"=*)"+
						")"
					);
				if(roots!=null)
					System.out.println("UPNP-DISCOVERER ---"+roots.length+" upnp devices found");
				else
					System.out.println("UPNP-DISCOVERER ---no UPnP devices found");
			
			}
			catch (InvalidSyntaxException e) {
				e.printStackTrace();
			}catch(Exception e){
				System.out.println("UAAA");
				e.printStackTrace();
			}
			if(roots!=null){
				for (int i = 0; i < roots.length; i++) {
					addNewDevice(roots[i]);
				}
			}
			listnersManager.init();
	}
	




	@Override
	public void serviceChanged(ServiceEvent event) {
		
	
		switch(event.getType()){
			case ServiceEvent.REGISTERED:{
				System.out.println("UPNP-DISCOVERER --- New UPnP device registered");
				addNewDevice(event.getServiceReference());
				break;
			}
			case ServiceEvent.MODIFIED:{
				System.out.println("UPNP-DISCOVERER --- UPnP device modified");
				
				//TODO ??
				break;
			}
			case ServiceEvent.UNREGISTERING:{	
				System.out.println("UPNP-DISCOVERER --- UPnP device unregistered");
				removeDevice(event.getServiceReference());
				break;		
			}
		}
		
	
	}


	private void removeDevice(ServiceReference serviceReference) {
		
		if(serviceReference.getProperty(UPnPDevice.MODEL_NAME).equals("Virtual Machine")){
			vmHypervisors.remove(serviceReference);
		}
		else if(serviceReference.getProperty(UPnPDevice.MODEL_NAME).equals("VM Hypervisor")){
			virtualMachines.remove(serviceReference);
		}
		else
			System.out.println("UPNP-DISCOVERER --- UPnP device of unknown type!");
			
		//		listnersManager.notifyAboutNewHypevisorDiscovered(new UPnPBasedHypervisor(device)); 

	}
	
	
	private void addNewDevice(ServiceReference serviceReference) {
	
		if(serviceReference.getProperty(UPnPDevice.MODEL_NAME).equals("VM Hypervisor")){
			
			vmHypervisors.add(serviceReference);
			Hypervisor hyp=new UPnPBasedHypervisor(serviceReference);
			System.out.println(hyp);
			listnersManager.notifyAboutNewHypevisorDiscovered(hyp);
			
		}
		else if(serviceReference.getProperty(UPnPDevice.MODEL_NAME).equals("Virtual Machine")){
			
			virtualMachines.add(serviceReference);
			VirtualMachine vm=new UPnPBasedVirtualMachine(serviceReference);
			System.out.println(vm);
			listnersManager.notifyAboutNewVMDiscovered(vm);
			
			
		}
		else
			System.out.println("UPNP-DISCOVERER --- UPnP device of unknown type!");
		
	
		
	}

	
	public static class DiscovererListenersManager implements ServiceListener{
		
		List<ServiceReference> discovererListeners=new ArrayList<ServiceReference>();
		
		public void init(){
			
			try{

				Activator.context.addServiceListener(this,
					"(&"+
					"("+Constants.OBJECTCLASS+"="+DiscovererListener.class.getName()+"))"
					);
				System.out.println("UPNP-DISCOVERER --- listener of discoverer clients activated");
				ServiceReference[] roots = null; 

				ServiceReference[] listeners;
				listeners= Activator.context.getServiceReferences(DiscovererListener.class.getName(), "(&"+
					"("+Constants.OBJECTCLASS+"="+DiscovererListener.class.getName()+"))");
				if(listeners!=null){
					System.out.println("UPNP-DISCOVERER --- "+listeners.length+" discoverer listeners found");
					
					for(ServiceReference dl:listeners){
						discovererListeners.add(dl);	
					}
				}
				else
					System.out.println("UPNP-DISCOVERER --- No discoverer listeners found");
			}catch (InvalidSyntaxException e) {
					e.printStackTrace();
			}
			
			
		}
		
		@Override
		public void serviceChanged(ServiceEvent event) {
			
			switch(event.getType()){
				case ServiceEvent.REGISTERED:{
					System.out.println("New discoverer listener registered");
					discovererListeners.add(event.getServiceReference());
					break;
				}
				case ServiceEvent.MODIFIED:{
					System.out.println("Discoverer listener modified");
					
					break;
				}
				case ServiceEvent.UNREGISTERING:{	
					System.out.println("Discoverer listener unregistered");
					discovererListeners.remove(event.getServiceReference());
					break;		
				}
			}
			
		}
		
		public void notifyAboutNewHypevisorDiscovered(Hypervisor hypervisor){
			for(ServiceReference sr:discovererListeners){
				
				DiscovererListener listener=(DiscovererListener)Activator.context.getService(sr);
				listener.hypervisorDiscovered(hypervisor);
				
			}
		}
		public void notifyAboutDeletedHypevisor(Hypervisor hypervisor){
			for(ServiceReference sr:discovererListeners){
				
				DiscovererListener listener=(DiscovererListener)Activator.context.getService(sr);
				listener.hypervisorDeleted(hypervisor);
				
			}
		}
		public void notifyAboutModifiedHypevisor(Hypervisor hypervisor){
			for(ServiceReference sr:discovererListeners){
				
				DiscovererListener listener=(DiscovererListener)Activator.context.getService(sr);
				listener.hypervisorModified(hypervisor);
				
			}	
		}
		public void notifyAboutNewVMDiscovered(VirtualMachine virtualMachine){
			for(ServiceReference sr:discovererListeners){
				
				DiscovererListener listener=(DiscovererListener)Activator.context.getService(sr);
				listener.vmDiscovered(virtualMachine);
				
			}
		}
		public void notifyAboutDeletedVM(VirtualMachine virtualMachine){
			for(ServiceReference sr:discovererListeners){
				
				DiscovererListener listener=(DiscovererListener)Activator.context.getService(sr);
				listener.vmDeleted(virtualMachine);
				
			}
		}
		
	}


}